package com.zyf.concurrency.chapter14;

/**
 * 使用条件队列实现的有界缓存
 * 引自原文：
 *      在程序清单14-6的BoundedBuffer中使用了wait 和notifyAll来实现-一个有界缓存。这比
 * 使用“休眠”的有界缓存更简单，并且更高效(当缓存状态没有发生变化时，线程醒来的次数
 * 将更少)，响应性也更高(当发生特定状态变化时将立即醒来)。这是一个较大的改进，但要注
 * 意:与使用“休眠”的有界缓存相比，条件队列并没有改变原来的语义。它只是在多个方面进
 * 行了优化: CPU效率、上下文切换开销和响应性等。如果某个功能无法通过“轮询和休眠”来
 * 实现，那么使用条件队列也无法实现，但条件队列使得在表达和管理状态依赖性时更加简单
 * 和高效。
 *      在产品的正式版本中还应包括限时版本的put和take,这样当阻塞操作不能在预计时间内完成
 * 时，可以因超时而返回。通过使用定时版本的Object.wait,可以很容易实现这些方法。
 * create by yifeng
 */
public class BoundedBuffer<V> extends BaseBoundedBuffer<V> {

    protected BoundedBuffer(int capacity) {
        super(capacity);
    }

    protected BoundedBuffer() {
        super(100);
    }

    // 阻塞并直到 ： not-full
    public synchronized void put(V v) throws InterruptedException {
        while (isFull()) {
            // 调用Object.wait()
            wait();
        }
        doPut(v);
        // 调用Object.notifyAll() 通知方法
        notifyAll();
    }

    // 阻塞并直到 ： not-empty
    public synchronized V take() throws InterruptedException {
        while (isEmpty()) {
            // 调用Object.wait()
            wait();
        }
        V v = doTake();
        // 调用Object.notifyAll() 通知方法
        notifyAll();
        return v;
    }

    /**
     * 程序清单14-8 在BoundedBuffer.put中使用条件通知
     * 首先，仅当缓存从空变为非空，或者从满转为非满时，才需要释放一个线程。并且，仅当put或take影响到这
     * 些状态转换时，才发出通知。这也被称为“条件通知( Conditional Notification)。
     */
    // 阻塞并直到 ： not-full
    // Alternate form of put() using conditional notification
    public synchronized void alternatePut(V v) throws InterruptedException {
        while (isFull())
            // 调用Object.wait()
            wait();
        boolean wasEmpty = isEmpty();
        doPut(v);
        if (wasEmpty)
        // 调用Object.notifyAll() 通知方法
            notifyAll();
    }
}
